<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <style>
        .box{width:330px;display: flex;align-items: center;}
        .box span{width:40px;text-align: center;}
        .box i{width:50px;text-align: center;}
        .myrange{width:200px;height:10px;border: solid 1px #aaa;background: #efefef;position: relative;border-radius: 6px;}
        .myrange p{margin: 0;background: #66f;width:10px;height:10px;border-radius: 5px;}
        .myrange p em{width:20px;height:20px;background: rgba(100,100,255,0.8);border-radius: 50%;position: absolute;left:0px;top:-5px}
    </style>
</head>
<body>
    <input type="range" step="20" value="10">

    <div class="box">
        <span>0</span>
        <i>0%</i>
        <div class="myrange">
            <p><em></em></p>
        </div>    
        <span>100</span>
    </div>
</body>
<script>

    const i = document.querySelector(".box i");
    const em = document.querySelector(".myrange em");
    const p = document.querySelector(".myrange p");
    const myrange = document.querySelector(".myrange");

    // 初始步长
    let step = 10;
    // 初始值
    // ....

    // 拖拽的基本逻辑
    em.onmousedown = function(eve){
        const downE = eve || window.event;
        // 保存起点
        let start = downE.pageX - downE.offsetX - myrange.offsetLeft;
        // 阻止默认事件，放置拖拽过程中，选中页面上的文字
        downE.preventDefault();
        document.onmousemove = function(eve){
            const moveE = eve || window.event;

            // 计算鼠标移动的距离
            let now = moveE.pageX - downE.offsetX - myrange.offsetLeft;

            // 边界限定：最小值
            if(now<0){
                now = 0;
                setStyle(now, "0");
            };
            // 边界限定：最大值
            if(now>myrange.offsetWidth-em.offsetWidth){
                now=myrange.offsetWidth-em.offsetWidth;
                setStyle(now, "100");
            }
            // 判断鼠标移动的距离是否大于步长：移动距离-起点 > 步长
            if(Math.abs(now - start) >= step){
                // 判断移动方向
                if(now - start > 0){
                    // 向右：将起点值增加（向右移动）
                    start+=step;
                }else{
                    // 向左：将起点值减少（向左移动）
                    start-=step;
                }
                // 将处理之后的距离设置到元素
                setStyle(start, Math.round(start / (myrange.offsetWidth-em.offsetWidth) * 100));
            }
        }
        document.onmouseup = function(){
            document.onmousemove = null;
            document.onmouseup = null;
        }
    }

    // 封装DOM操作
    function setStyle(value, num){
        em.style.left = value + "px";
        p.style.width = value + 10 + "px";
        i.innerHTML = num + "%";
    }
    
</script>
</html>